﻿using System;
using System.Collections.Generic;
using NHibernate.Mapping.ByCode;
using Xenta.Enums;
using Xenta.Structs;

namespace Xenta.Entities
{
    /// <summary>
    /// Represents the country entity.
    /// </summary>
    /// <remarks><pre>
    /// The entity regarding the disclosure level.
    /// 
    /// + Entire
    ///  + Extended
    ///   | - DateFormat
    ///   | - TimeFormat
    ///   | - DateTimeFormat
    ///   | - NumericFormat
    ///   + Base
    ///    | - Name
    ///    | - Flags
    ///    | - CreatedOn
    ///    | - UpdatedOn
    ///    + Keys
    ///     | - Code
    ///     + Primary
    ///      | - EntityID
    /// 
    /// Note: upper level includes lower level.
    /// </pre></remarks>
    public class CountryEntity : AuditableEntity
    {
        #region Fields

        private ICollection<RegionEntity> _regions;

        #endregion

        #region Ctors

        /// <summary>
        /// Initializes a new class instance.
        /// </summary>
        public CountryEntity()
        {
            _regions = new List<RegionEntity>();
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets the code.
        /// </summary>
        /// <remarks>
        /// ISO 3166-2
        /// </remarks>
        public virtual string Code
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the name.
        /// </summary>
        public virtual string Name
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the date format.
        /// </summary>
        public virtual string DateFormat
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the time format.
        /// </summary>
        public virtual string TimeFormat
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the raw numeric format.
        /// </summary>
        public virtual string RawNumericFormat
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the numeric format.
        /// </summary>
        public virtual NumericFormat NumericFormat
        {
            get
            {
                return NumericFormat.Parse(RawNumericFormat);
            }
            set
            {
                RawNumericFormat = value.ToString();
            }
        }

        /// <summary>
        /// Gets or sets the flags.
        /// </summary>
        public virtual CountryFlags Flags
        {
            get;
            set;
        }

        #endregion

        #region Collections

        /// <summary>
        /// Gets or sets collection of regions.
        /// </summary>
        public virtual ICollection<RegionEntity> Regions
        {
            get
            {
                return _regions;
            }
            set
            {
                _regions = value;
            }
        }

        #endregion

        #region Custom Properties

        /// <summary>
        /// Gets the date/time format.
        /// </summary>
        public virtual string DateTimeFormat
        {
            get
            {
                return String.Format("{0} {1}", DateFormat, TimeFormat);
            }
        }

        #endregion

        #region Utilities

        protected override void Disclose(IDictionary<String, Object> obj,
            DisclosureLevel level,
            IDictionary<String, String> options)
        {
            base.Disclose(obj, level, options);
            if(level >= DisclosureLevel.Keys)
                obj["Code"] = Code;
            if(level >= DisclosureLevel.Base)
            {
                obj["Name"] = Name;
                obj["Flags"] = Flags.ToString();
            }
            if(level >= DisclosureLevel.Extended)
            {
                obj["DateFormat"] = DateFormat;
                obj["TimeFormat"] = TimeFormat;
                obj["DateTimeFormat"] = DateTimeFormat;
                obj["NumericFormat"] = NumericFormat;
            }
        }

        #endregion
    }

    /// <summary>
    /// The entity NHibernate mapper.
    /// </summary>
    public class CountryMapping : EntityMapping<CountryEntity>
    {
        /// <summary>
        /// Initializes a new class instance.
        /// </summary>
        public CountryMapping()
        {
            Table("fwk_Countries");
            Id(x => x.EntityID, m =>
            {
                m.Column("CountryID");
                m.Generator(Generators.Identity);
            });
            Property(x => x.Code, m =>
            {
                m.NotNullable(true);
                m.Length(2);
                m.Unique(true);
                m.Index("IX_fwk_Countries");
                m.Column(c =>
                {
                    c.SqlType("nchar(2)");
                });
            });
            Property(x => x.Name, m =>
            {
                m.NotNullable(true);
                m.Length(100);
                m.Column(c =>
                {
                    c.SqlType("nvarchar(100)");
                });
            });
            Property(x => x.DateFormat, m =>
            {
                m.NotNullable(true);
                m.Length(100);
                m.Column(c =>
                {
                    c.SqlType("nvarchar(100)");
                });
            });
            Property(x => x.TimeFormat, m =>
            {
                m.NotNullable(true);
                m.Length(100);
                m.Column(c =>
                {
                    c.SqlType("nvarchar(100)");
                });
            });
            Property(x => x.RawNumericFormat, m =>
            {
                m.NotNullable(true);
                m.Length(100);
                m.Column(c =>
                {
                    c.Name("NumericFormat");
                    c.SqlType("nvarchar(100)");
                });
            });
            Property(x => x.Flags, m =>
            {
                m.NotNullable(true);
            });
            Property(x => x.CreatedOn, m =>
            {
                m.NotNullable(true);
            });
            Property(x => x.UpdatedOn, m =>
            {
                m.NotNullable(true);
            });
            Bag(x => x.Regions, m =>
            {
                m.Table("fwk_Regions");
                m.Key(k =>
                {
                    k.Column("CountryID");
                    k.ForeignKey("FK_fwk_Regions_fwk_Countries");
                    k.NotNullable(true);
                });
                m.Inverse(true);
            },
            a =>
            {
                a.OneToMany();
            });
            Cache(m =>
            {
                m.Usage(CacheUsage.ReadWrite);
            });
        }
    }
}
